/**
 * Date: 2013-5-29
 * <p>
 * Copyright (C) 2013-2015 7Road. All rights reserved.
 */

package com.nirvana.utils;

import com.nirvana.config.PluginConfig;
import com.nirvana.convert.CamelCaseConverter;
import com.nirvana.data.DaoGenerateContext;
import com.nirvana.data.DbFieldInfo;
import com.nirvana.generate.OrmEntityGenerator;
import com.nirvana.type.DaoOption;

import java.util.*;

/**
 * 20130604修改一： 当主键为自增长的时候，添加脚本不应该设置该主键的值
 *
 * @author jinjin.chen
 */
public class DaoCodeUtil {

    public static String generateDaoImplCode() {
        DaoGenerateContext context = OrmEntityGenerator.context;
        StringBuilder result = new StringBuilder();
        result.append("""
                package %s;
                
                import java.sql.Connection;
                import java.sql.PreparedStatement;
                import java.sql.ResultSet;
                import java.sql.SQLException;
                import java.sql.Types;
                import java.util.List;
                import com.nirvana.database.dao.BaseDao;
                import com.nirvana.database.DBParamWrapper;
                import com.nirvana.database.DataExecutor;
                import com.nirvana.database.DBHelper;
                import com.nirvana.database.DataOption;
                import %s.%s;
                import %s.%s;
                
                public class %s extends BaseDao<%s> implements %s {
                    public %s(DBHelper helper) {
                        super(helper);
                    }
                
                    @Override
                    public boolean add(%s %s) {
                        int id = -1;
                        String sql = %s;
                        DBParamWrapper params = new DBParamWrapper();
                %s
                %s
                    }
                """.formatted(
                PluginConfig.getInstance().getDaoImplPackage(),
                PluginConfig.getInstance().getDaoPackage(),
                CommonUtil.CreateInterfaceName(context.entityName),
                PluginConfig.getInstance().getEntityPackage(),
                context.entityName,
                CommonUtil.CreateImplName(context.entityName),
                context.entityName,
                CommonUtil.CreateInterfaceName(context.entityName),
                CommonUtil.CreateImplName(context.entityName),
                context.entityName,
                context.lowEntityName,
                createInsertSql(context.tableName, context.fields),
                createSqlParams(context.entityName, context.fields),
                createAddReturn()
        ));
        /* update方法 */
        result.append(generateUpdateMethod()).append("\n\n");
        /* delete方法 */
        result.append(generateDeleteMethod()).append("\n\n");
        /* addOrUpdate方法 */
        result.append(generateAddOrUpdateMethod()).append("\n\n");
        /* DeleteByKey方法 */
        result.append(genrerateDeleteByKeymethod()).append("\n\n");
        /* GetByKey方法 */
        result.append(generateGetByKeyMethod()).append("\n\n");
        /* ListAll方法 */
        result.append(generateListAllMethod()).append("\n");
        /* addOrUpdateBatch方法 */
        result.append(generateaddOrUpdateBatchMethod()).append("\n").append("\n");

        result.append(generateAddBatchMethod()).append("\n").append("\n");
        result.append(generateUpdateBatchMethod()).append("\n");

        /* deleteBatch方法 */
        result.append(generatedeleteBatchMethod()).append("\n");
        /* rsToEntity方法 */
        result.append(generatersToEntityMethod()).append("\n");
        /* } */

        if (context.options.get(DaoOption.GET_ENTITY_LIST_BY_FIST_PRIMARY_KEY)) {
            result.append(generateGetEntityByFirstPrimaryKey()).append("\n");
        }

        result.append("}");
        return result.toString();
    }

    private static String generateGetEntityByFirstPrimaryKey() {
        DaoGenerateContext context = OrmEntityGenerator.context;
        String entityName = context.entityName;
        String tableName = context.tableName;
        List<DbFieldInfo> primaryFields = context.primaryFields.stream().findFirst().stream().toList();
        DbFieldInfo fieldInfo = primaryFields.get(0);
        return """
                    @Override
                    public List<%s> get%sListBy%s(%s) {
                        String sql = "select * from %s where %s;";
                        DBParamWrapper params = new DBParamWrapper();
                %s
                        return queryList(sql, params);
                    }
                """.formatted(
                entityName,
                entityName,
                CommonUtil.createPrimaryMethodName(primaryFields),
                CommonUtil.createPrimaryMethodParams(primaryFields),
                tableName,
                createPrimarySqlParams(primaryFields),
                createSetParams("params", fieldInfo.getColumnName(), fieldInfo.getSqlType())
        );
    }

    private static String createPrimarySqlParams(List<DbFieldInfo> primaryFieldInfos) {
        List<String> list = primaryFieldInfos.stream().map(info -> info.getColumnName() + "= ?").toList();
        return String.join(" and ", list);
    }

    private static String generatersToEntityMethod() {
        DaoGenerateContext context = OrmEntityGenerator.context;
        String entityName = context.entityName;
        List<DbFieldInfo> fields = context.fields;
        String scope = "public";
        String _return = CommonUtil.CreateEntityName(entityName);
        String methodName = "rsToEntity";
        String params = "ResultSet rs";
        StringBuilder sb = new StringBuilder();
        sb.append("\t").append("@Override").append("\n");
        sb.append("\t").append(generateMethod(scope, _return, methodName, params) + " throws SQLException")
                .append("\n");
        sb.append("\t").append("{").append("\n");
        sb.append("\t\t")
                .append(CommonUtil.CreateEntityName(entityName) + " "
                        + CommonUtil.CreateEntityParameterName(entityName) + " = new "
                        + CommonUtil.CreateEntityName(entityName) + "();")
                .append("\n");
        for (int i = 0; i < fields.size(); i++) {
            sb.append("\t\t").append(createSet(CommonUtil.CreateEntityParameterName(entityName),
                    fields.get(i).getColumnName(), fields.get(i).getJavaType()));
        }
        sb.append("\t\t").append(CommonUtil.CreateEntityParameterName(entityName))
                .append(".setOp(DataOption.NONE);").append("\n");
        sb.append("\t\t").append("return " + CommonUtil.CreateEntityParameterName(entityName)).append(";\n");
        sb.append("\t").append("}").append("\n");
        return sb.toString();
    }

    private static String generatedeleteBatchMethod() {
        DaoGenerateContext context = OrmEntityGenerator.context;
        String entityName = context.entityName;
        String tableName = context.tableName;
        List<DbFieldInfo> fields = context.fields;
        String scope = "public";
        String _return = "int[]";
        String methodName = "deleteBatch";
        String params = "List<" + CommonUtil.CreateEntityName(entityName) + "> "
                + CommonUtil.CreateEntityPluralParaName(entityName);
        StringBuilder sb = new StringBuilder();
        sb.append("\t").append("@Override").append("\n");
        sb.append("\t").append(generateMethod(scope, _return, methodName, params)).append("\n");
        sb.append("\t").append("{").append("\n");
        sb.append("\t\t").append("String sql = " + createDeleteSql(tableName, fields) + ";").append("\n");

        sb.append("\t\t")
                .append("int[] effectedRows = getDBHelper().sqlBatch(sql, "
                        + CommonUtil.CreateEntityPluralParaName(entityName) + ", new DataExecutor<int[]>()")
                .append("\n");
        sb.append("\t\t").append("{").append("\n");
        sb.append("\t\t\t").append("@Override").append("\n");
        sb.append("\t\t")
                .append("public int[] execute(PreparedStatement statement, Object... objects) throws Exception")
                .append("\n");
        sb.append("\t\t").append("{").append("\n");
        sb.append("\t\t\t").append("").append("\n");
        sb.append("\t\t\t").append("@SuppressWarnings(\"unchecked\")").append("\n");
        sb.append("\t\t\t")
                .append("List<" + CommonUtil.CreateEntityName(entityName) + ">"
                        + CommonUtil.CreateEntityPluralParaName(entityName) + " = (List<"
                        + CommonUtil.CreateEntityName(entityName) + ">)objects[0];")
                .append("\n");

        sb.append("\t\t\t")
                .append("for (" + CommonUtil.CreateEntityName(entityName) + " "
                        + CommonUtil.CreateEntityParameterName(entityName) + " : "
                        + CommonUtil.CreateEntityPluralParaName(entityName) + ")")
                .append("\n");
        sb.append("\t\t\t").append("{").append("\n");
        sb.append("\t\t\t\t\t").append("DBParamWrapper params = new DBParamWrapper();").append("\n");

        for (int i = 0; i < fields.size(); i++) {
            if (! fields.get(i).isPrimaryKey()) {
                continue;
            }
            sb.append("\t\t\t\t\t").append(createSetParams("params", fields.get(i).getColumnName(),
                    fields.get(i).getSqlType(), entityName)).append("\n");
        }

        sb.append("\t\t\t\t\t").append("statement = getDBHelper().prepareCommand(statement,params.getParams());")
                .append("\n");
        sb.append("\t\t\t\t\t").append("statement.addBatch();").append("\n");
        sb.append("\t\t\t\t").append("}").append("\n");
        sb.append("\t\t\t\t").append("return statement.executeBatch();").append("\n");
        sb.append("\t\t\t").append("}").append("\n");
        sb.append("\t\t").append("});").append("\n");
        sb.append("\t\t").append("return effectedRows;").append("\n");
        sb.append("\t").append("}");

        return sb.toString();
    }

    private static String generateaddOrUpdateBatchMethod() {
        DaoGenerateContext context = OrmEntityGenerator.context;
        String entityName = context.entityName;
        String tableName = context.tableName;
        List<DbFieldInfo> fields = context.fields;
        String scope = "public";
        String _return = "int[]";
        String methodName = "addOrUpdateBatch";
        String params = "List<" + CommonUtil.CreateEntityName(entityName) + "> "
                + CommonUtil.CreateEntityPluralParaName(entityName);
        StringBuilder sb = new StringBuilder();
        sb.append("\t").append("@Override").append("\n");
        sb.append("\t").append(generateMethod(scope, _return, methodName, params)).append("\n");
        sb.append("\t").append("{").append("\n");
        sb.append("\t\t").append("String sql = " + createaddOrUpdateSql(tableName, fields) + ";").append("\n");
        sb.append("\t\t")
                .append("int[] effectedRows = getDBHelper().sqlBatch(sql, "
                        + CommonUtil.CreateEntityPluralParaName(entityName) + ", new DataExecutor<int[]>()")
                .append("\n");
        sb.append("\t\t\t").append("{").append("\n");
        sb.append("\t\t\t\t").append("@Override").append("\n");
        sb.append("\t\t\t\t")
                .append("public int[] execute(PreparedStatement statement, Object... objects) throws Exception")
                .append("\n");
        sb.append("\t\t\t\t").append("{").append("\n");
        sb.append("\t\t\t\t\t").append("@SuppressWarnings(\"unchecked\")").append("\n");
        sb.append("\t\t\t\t\t")
                .append("List<" + CommonUtil.CreateEntityName(entityName) + ">"
                        + CommonUtil.CreateEntityPluralParaName(entityName) + " = (List<"
                        + CommonUtil.CreateEntityName(entityName) + ">)objects[0];")
                .append("\n");

        sb.append("\t\t\t\t\t")
                .append("for (" + CommonUtil.CreateEntityName(entityName) + " "
                        + CommonUtil.CreateEntityParameterName(entityName) + " : "
                        + CommonUtil.CreateEntityPluralParaName(entityName) + ")")
                .append("\n");
        sb.append("\t\t\t\t\t").append("{").append("\n");
        sb.append("\t\t\t\t\t\t").append("DBParamWrapper params = new DBParamWrapper();").append("\n");
        // int tag = 1;
        for (int i = 0; i < fields.size(); i++) {
            // if (!fields.get(i).isAotuIncreamte())
            // {
            sb.append("\t\t\t\t\t\t").append(createSetParams("params", fields.get(i).getColumnName(),
                    fields.get(i).getSqlType(), entityName)).append("\n");
            // tag++;
            // }
        }
        for (int i = 0; i < fields.size(); i++) {
            if (fields.get(i).isPrimaryKey()) {
                continue;
            }
            sb.append("\t\t\t\t\t\t").append(createSetParams("params", fields.get(i).getColumnName(),
                    fields.get(i).getSqlType(), entityName)).append("\n");
            // tag++;
        }
        sb.append("\t\t\t\t\t\t").append("statement = getDBHelper().prepareCommand(statement,params.getParams());")
                .append("\n");
        sb.append("\t\t\t\t\t\t").append("statement.addBatch();").append("\n");
        sb.append("\t\t\t\t\t").append("}").append("\n");
        sb.append("\t\t\t\t\t").append("return statement.executeBatch();").append("\n");
        sb.append("\t\t\t\t").append("}").append("\n");
        sb.append("\t\t\t").append("});").append("\n");
        sb.append("\t\t").append("return effectedRows;").append("\n");
        sb.append("\t").append("}");
        return sb.toString();

    }

    private static String generateAddBatchMethod() {
        DaoGenerateContext context = OrmEntityGenerator.context;
        String entityName = context.entityName;
        String tableName = context.tableName;
        List<DbFieldInfo> fields = context.fields;
        String scope = "public";
        String _return = "void";
        String methodName = "addBatch";
        String params = "List<" + CommonUtil.CreateEntityName(entityName) + "> "
                + CommonUtil.CreateEntityPluralParaName(entityName) + ", Connection conn";
        String sql = createInsertSql(tableName, fields);
        sql = sql.substring(0, sql.length() - 2);
        StringBuilder sb = new StringBuilder();
        sb.append("\t").append("@Override").append("\n");
        sb.append("\t").append(generateMethod(scope, _return, methodName, params)).append(" throws SQLException")
                .append("\n");
        sb.append("\t").append("{").append("\n");
        sb.append("\t\t").append("String sql = " + sql).append("\";\n");
        sb.append("\t\t").append(
                "PreparedStatement statement = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY);\n");

        sb.append("\t\t")
                .append("for (" + CommonUtil.CreateEntityName(entityName) + " "
                        + CommonUtil.CreateEntityParameterName(entityName) + " : "
                        + CommonUtil.CreateEntityPluralParaName(entityName) + ")")
                .append("\n");
        sb.append("\t\t").append("{").append("\n");
        sb.append("\t\t\t").append("DBParamWrapper params = new DBParamWrapper();").append("\n");
        // int tag = 1;
        for (int i = 0; i < fields.size(); i++) {
            if (! fields.get(i).isAutoIncrement()) {
                sb.append("\t\t\t").append(createSetParams("params", fields.get(i).getColumnName(),
                        fields.get(i).getSqlType(), entityName)).append("\n");
                // tag++;
            }
        }

        sb.append("\t\t\t").append("statement = getDBHelper().prepareCommand(statement,params.getParams());")
                .append("\n");
        sb.append("\t\t\t").append("statement.addBatch();").append("\n");
        sb.append("\t\t").append("}").append("\n");
        sb.append("\t\t").append("statement.executeBatch();").append("\n");
        sb.append("\t\t").append("super.close(statement);").append("\n");
        sb.append("\t").append("}").append("\n");
        return sb.toString();
    }

    private static String generateUpdateBatchMethod() {
        DaoGenerateContext context = OrmEntityGenerator.context;
        String entityName = context.entityName;
        String tableName = context.tableName;
        List<DbFieldInfo> fields = context.fields;
        String scope = "public";
        String _return = "void";
        String methodName = "updateBatch";
        String params = "List<" + CommonUtil.CreateEntityName(entityName) + "> "
                + CommonUtil.CreateEntityPluralParaName(entityName) + ", Connection conn";
        String sql = createUpdateSql(tableName, fields);
        sql = sql.substring(0, sql.length() - 2);
        StringBuilder sb = new StringBuilder();
        sb.append("\t").append("@Override").append("\n");
        sb.append("\t").append(generateMethod(scope, _return, methodName, params)).append(" throws SQLException")
                .append("\n");
        sb.append("\t").append("{").append("\n");
        sb.append("\t\t").append("String sql = " + sql).append("\";\n");
        sb.append("\t\t").append(
                "PreparedStatement statement = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY);\n");

        sb.append("\t\t")
                .append("for (" + CommonUtil.CreateEntityName(entityName) + " "
                        + CommonUtil.CreateEntityParameterName(entityName) + " : "
                        + CommonUtil.CreateEntityPluralParaName(entityName) + ")")
                .append("\n");
        sb.append("\t\t").append("{").append("\n");
        sb.append("\t\t\t").append("DBParamWrapper params = new DBParamWrapper();").append("\n");

        List<DbFieldInfo> keys = new ArrayList<DbFieldInfo>();
        // int tag = 1;
        for (int i = 0; i < fields.size(); i++) {
            if (fields.get(i).isPrimaryKey()) {
                keys.add(fields.get(i));
                continue;
            }
            sb.append("\t\t\t").append(createSetParams("params", fields.get(i).getColumnName(), fields.get(i).getSqlType(),
                    entityName)).append("\n");
            // tag++;
        }
        for (DbFieldInfo fieldInfo : keys) {
            sb.append("\t\t\t").append(
                            createSetParams("params", fieldInfo.getColumnName(), fieldInfo.getSqlType(), entityName))
                    .append("\n");
            // tag++;
        }

        sb.append("\t\t\t").append("statement = getDBHelper().prepareCommand(statement,params.getParams());")
                .append("\n");
        sb.append("\t\t\t").append("statement.addBatch();").append("\n");
        sb.append("\t\t").append("}").append("\n");
        sb.append("\t\t").append("statement.executeBatch();").append("\n");
        sb.append("\t\t").append("super.close(statement);").append("\n");
        sb.append("\t").append("}").append("\n");
        return sb.toString();
    }

    private static Object genrerateDeleteByKeymethod() {
        DaoGenerateContext context = OrmEntityGenerator.context;
        String entityName = context.entityName;
        String tableName = context.tableName;
        List<DbFieldInfo> fields = context.fields;
        String scope = "public";
        String _return = "boolean";
        String methodName = "deleteByKey";
        String params = "Object... ids";
        StringBuilder sb = new StringBuilder();
        sb.append("\t").append("@Override").append("\n");
        sb.append("\t").append(generateMethod(scope, _return, methodName, params)).append("\n");
        sb.append("\t").append("{").append("\n");
        // sb.append("\t\t").append("boolean result = false;").append("\n");
        sb.append("\t\t").append("String sql = " + createDeleteSql(tableName, fields) + ";").append("\n");
        sb.append("\t\t").append("DBParamWrapper params = new DBParamWrapper();").append("\n");
        for (int i = 0; i < fields.size(); i++) {
            if (! fields.get(i).isPrimaryKey()) {
                continue;
            }
            sb.append("\t\t").append(createSetParams("params", "ids", fields.get(i).getSqlType(), i)).append("\n");
        }
        sb.append("\t\t").append("return update(sql, params);").append("\n");
        // sb.append("\t\t").append("return result;").append("\n");
        sb.append("\t").append("}");
        return sb.toString();
    }

    private static String generateGetByKeyMethod() {
        DaoGenerateContext context = OrmEntityGenerator.context;
        String entityName = context.entityName;
        String tableName = context.tableName;
        List<DbFieldInfo> fields = context.fields;
        String scope = "public";
        String _return = CommonUtil.CreateEntityName(entityName);
        String methodName = "getByKey";
        String params = "Object... ids";

        StringBuilder sb = new StringBuilder();
        sb.append("\t").append("@Override").append("\n");
        sb.append("\t").append(generateMethod(scope, _return, methodName, params)).append("\n");
        sb.append("\t").append("{").append("\n");
        sb.append("\t\t").append("String sql = " + createGetByIDSql(tableName, fields) + ";").append("\n");
        sb.append("\t\t").append("DBParamWrapper params = new DBParamWrapper();").append("\n");
        for (int i = 0; i < fields.size(); i++) {
            if (! fields.get(i).isPrimaryKey()) {
                continue;
            }
            sb.append("\t\t").append(createSetParams("params", "ids", fields.get(i).getSqlType(), i)).append("\n");
        }
        sb.append("\t\t").append(CommonUtil.CreateEntityName(entityName) + " "
                + CommonUtil.CreateEntityParameterName(entityName) + " = query(sql, params);\n");
        sb.append("\t\t").append("return " + CommonUtil.CreateEntityParameterName(entityName) + ";")
                .append("\n");
        sb.append("\t").append("}").append("\n");
        return sb.toString();
    }

    /**
     * @return
     */
    private static String generateAddOrUpdateMethod() {
        DaoGenerateContext context = OrmEntityGenerator.context;
        String entityName = context.entityName;
        String tableName = context.tableName;
        List<DbFieldInfo> fields = context.fields;
        String scope = "public";
        String _return = "boolean";
        String methodName = "addOrUpdate";
        String params = generateParam(entityName);
        StringBuilder sb = new StringBuilder();
        sb.append("\t").append("@Override").append("\n");
        sb.append("\t").append(generateMethod(scope, _return, methodName, params)).append("\n");
        sb.append("\t").append("{").append("\n");
        // sb.append("\t\t").append("boolean result = false;").append("\n");
        sb.append("\t\t").append("String sql = " + createaddOrUpdateSql(tableName, fields) + ";").append("\n");
        sb.append("\t\t").append("DBParamWrapper params = new DBParamWrapper();").append("\n");
        // int tag = 1;
        for (int i = 0; i < fields.size(); i++) {
            // if (!fields.get(i).isAotuIncreamte())
            // {
            sb.append("\t\t").append(createSetParams("params", fields.get(i).getColumnName(), fields.get(i).getSqlType(),
                    entityName)).append("\n");
            // tag++;
            // }
        }
        for (int i = 0; i < fields.size(); i++) {
            if (fields.get(i).isPrimaryKey()) {
                continue;
            }
            sb.append("\t\t").append(createSetParams("params", fields.get(i).getColumnName(), fields.get(i).getSqlType(),
                    entityName)).append("\n");
            // tag++;
        }
        sb.append("\t\t").append("return update(sql, params);").append("\n");
        // sb.append("\t\t").append("return result;").append("\n");
        sb.append("\t").append("}");
        return sb.toString();
    }

    private static String generateListAllMethod() {
        DaoGenerateContext context = OrmEntityGenerator.context;
        String entityName = context.entityName;
        String tableName = context.tableName;
        String scope = "public";
        String _return = "List<" + CommonUtil.CreateEntityName(entityName) + ">";
        String methodName = "listAll";
        String params = "";

        StringBuilder sb = new StringBuilder();
        sb.append("\t").append("@Override").append("\n");
        sb.append("\t").append(generateMethod(scope, _return, methodName, params)).append("\n");
        sb.append("\t").append("{").append("\n");
        sb.append("\t\t").append("String sql = \"select * from " + tableName + ";\"").append(";\n");
        sb.append("\t\t").append("List<" + CommonUtil.CreateEntityName(entityName) + "> "
                + CommonUtil.CreateEntityPluralParaName(entityName) + " = queryList(sql);\n");
        sb.append("\t\t").append("return " + CommonUtil.CreateEntityPluralParaName(entityName) + ";")
                .append("\n");
        sb.append("\t").append("}").append("\n");

        return sb.toString();
    }

    private static String generateDeleteMethod() {
        DaoGenerateContext context = OrmEntityGenerator.context;
        String entityName = context.entityName;
        String tableName = context.tableName;
        List<DbFieldInfo> fields = context.fields;
        String scope = "public";
        String _return = "boolean";
        String methodName = "delete";
        String params = generateParam(entityName);
        StringBuilder sb = new StringBuilder();
        sb.append("\t").append("@Override").append("\n");
        sb.append("\t").append(generateMethod(scope, _return, methodName, params)).append("\n");
        sb.append("\t").append("{").append("\n");
        // sb.append("\t\t").append("boolean result = false;").append("\n");
        sb.append("\t\t").append("String sql = " + createDeleteSql(tableName, fields) + ";").append("\n");
        sb.append("\t\t").append("DBParamWrapper params = new DBParamWrapper();").append("\n");
        for (int i = 0; i < fields.size(); i++) {
            if (! fields.get(i).isPrimaryKey()) {
                continue;
            }
            sb.append("\t\t").append(createSetParams("params", fields.get(i).getColumnName(), fields.get(i).getSqlType(),
                    entityName)).append("\n");
        }
        sb.append("\t\t").append("return update(sql, params);").append("\n");
        // sb.append("\t\t").append("return result;").append("\n");
        sb.append("\t").append("}");
        return sb.toString();
    }

    private static String generateUpdateMethod() {
        DaoGenerateContext context = OrmEntityGenerator.context;
        String entityName = context.entityName;
        String tableName = context.tableName;
        List<DbFieldInfo> fields = context.fields;
        String scope = "public";
        String _return = "boolean";
        String methodName = "update";
        String params = generateParam(entityName);
        StringBuilder sb = new StringBuilder();
        sb.append("\t").append("@Override").append("\n");
        sb.append("\t").append(generateMethod(scope, _return, methodName, params)).append("\n");
        sb.append("\t").append("{").append("\n");
        sb.append("\t\t").append("String sql = " + createUpdateSql(tableName, fields) + ";").append("\n");
        sb.append("\t\t").append("DBParamWrapper params = new DBParamWrapper();").append("\n");
        List<DbFieldInfo> keys = new ArrayList<DbFieldInfo>();
        for (int i = 0; i < fields.size(); i++) {
            if (fields.get(i).isPrimaryKey()) {
                keys.add(fields.get(i));
                continue;
            }
            sb.append("\t\t").append(createSetParams("params", fields.get(i).getColumnName(), fields.get(i).getSqlType(),
                    entityName)).append("\n");
        }
        for (DbFieldInfo fieldInfo : keys) {
            sb.append("\t\t").append(
                            createSetParams("params", fieldInfo.getColumnName(), fieldInfo.getSqlType(), entityName))
                    .append("\n");
        }
        sb.append("\t\t").append("return update(sql, params);").append("\n");
        sb.append("\t").append("}");
        return sb.toString();
    }

    private static String generateAddMethod(String entityName, String tableName, List<DbFieldInfo> fields) {
        String scope = "public";
        String _return = "boolean";
        String methodName = "add";
        String params = generateParam(entityName);
        StringBuilder sb = new StringBuilder();
        sb.append("\t").append("@Override").append("\n");
        sb.append("\t").append(generateMethod(scope, _return, methodName, params)).append("\n");
        sb.append("\t").append("{").append("\n");
        sb.append("\t\t").append("String sql = " + createInsertSql(tableName, fields) + ";").append("\n");
        sb.append("\t\t").append("DBParamWrapper params = new DBParamWrapper();").append("\n");
        for (int i = 0; i < fields.size(); i++) {
            if (! fields.get(i).isAutoIncrement()) {
                sb.append("\t\t").append(createSetParams("params", fields.get(i).getColumnName(), fields.get(i).getSqlType(),
                        entityName)).append("\n");
            }
        }
        sb.append("\t\t").append("return update(sql, params);").append("\n");
        sb.append("\t").append("}");
        return sb.toString();
    }

    private static String autoIncrementAddMethod(String entityName, String tableName, List<DbFieldInfo> fields) {
        return """
                    @Override
                    public boolean add(%s %s) {
                        int id = -1;
                        String sql = %s;
                        DBParamWrapper params = new DBParamWrapper();
                %s
                %s
                    }
                """.formatted(
                entityName,
                CommonUtil.toLowerName(entityName),
                createInsertSql(tableName, fields),
                createSqlParams(entityName, fields),
                createAddReturn()
        );
    }

    private static String createAddReturn() {
        DaoGenerateContext context = OrmEntityGenerator.context;
        if (context.options.get(DaoOption.AUTO_INCREMENT)) {
            return """
                            id = add(sql, params);
                            %s.setId(id);
                            return id > 0;
                    """.formatted(context.lowEntityName);
        }
        return """
                        return update(sql, params);
                """;
    }

    private static String createSqlParams(String entityName, List<DbFieldInfo> fields) {
        StringBuilder content = new StringBuilder();
        for (DbFieldInfo field : fields) {
            if (! field.isAutoIncrement()) {
                content.append("""
                                %s
                        """.formatted(
                        createSetParams("params", field.getColumnName(), field.getSqlType(), entityName)

                ));
            }
        }
        return content.toString();
    }

    private static String generateConstructor(String entityName, String tableName) {
        StringBuilder result = new StringBuilder();
        result.append("\t").append("public " + CommonUtil.CreateImplName(entityName) + "(DBHelper helper)")
                .append("\n");
        result.append("\t").append("{").append("\n");
        result.append("\t\t").append("super(helper);").append("\n");
        result.append("\t").append("}").append("\n");
        return result.toString();
    }

    // /**
    // * @param entityName
    // * @return
    // */
    // private static String generateLogger(String entityName, String tableName)
    // {
    // StringBuilder result = new StringBuilder();
    // result.append(
    // "private static final Logger LOGGER = LoggerFactory.getLogger("
    // + CommonUtil.CreateImplName(entityName, tableName)
    // + ".class)").append(";");
    // return result.toString();
    // }

    private static String generateImplementName(String entityName, String tableName) {
        StringBuilder result = new StringBuilder();
        result.append("public class " + CommonUtil.CreateImplName(entityName) + " extends BaseDao<"
                + CommonUtil.CreateEntityName(entityName) + "> implements "
                + CommonUtil.CreateInterfaceName(entityName));
        return result.toString();
    }

    private static String generateParam(String entityName) {
        return CommonUtil.CreateEntityName(entityName) + " "
                + CommonUtil.CreateEntityParameterName(entityName);
    }

    private static String generateMethod(String scope, String _return, String methodName, String params) {
        StringBuilder sb = new StringBuilder();
        sb.append(scope + " " + _return + " " + methodName + "(" + params + ")");
        return sb.toString();
    }

    private static String createInsertSql(String tableName, List<DbFieldInfo> fields) {
        StringBuilder sql = new StringBuilder();
        sql.append("\"insert into " + tableName);
        sql.append("(");
        for (int i = 0; i < fields.size(); i++) {
            if (! fields.get(i).isAutoIncrement()) {
                sql.append("`").append(fields.get(i).getColumnName()).append("`, ");
            }
        }
        sql.delete(sql.length() - 2, sql.length());

        sql.append(") values(");
        for (int i = 0; i < fields.size(); i++) {
            if (! fields.get(i).isAutoIncrement()) {
                sql.append("?, ");
            }
        }
        sql.delete(sql.length() - 2, sql.length());

        sql.append(");\"");
        return sql.toString();
    }

    private static String createUpdateSql(String tableName, List<DbFieldInfo> fields) {
        StringBuilder sql = new StringBuilder();
        sql.append("\"update " + tableName + " set ");
        for (int i = 0; i < fields.size(); i++) {
            if (fields.get(i).isPrimaryKey()) {
                continue;
            }
            sql.append("`").append(fields.get(i).getColumnName()).append("`=?, ");
        }
        sql.delete(sql.length() - 2, sql.length());

        sql.append(" where ");
        for (int i = 0; i < fields.size(); i++) {
            if (! fields.get(i).isPrimaryKey()) {
                continue;
            }
            sql.append("`").append(fields.get(i).getColumnName()).append("`=?");
            sql.append(" and ");
        }
        if (sql.lastIndexOf(" and ") > 0) {
            sql.delete(sql.length() - 5, sql.length());
        }

        sql.append(";\"");
        return sql.toString();
    }

    private static String createaddOrUpdateSql(String tableName, List<DbFieldInfo> fields) {
        StringBuilder sql = new StringBuilder();
        sql.append("\"insert into " + tableName);
        sql.append("(");
        for (int i = 0; i < fields.size(); i++) {
            sql.append("`").append(fields.get(i).getColumnName()).append("`, ");
        }
        sql.delete(sql.length() - 2, sql.length());

        sql.append(") values(");
        sql.append("?, ".repeat(fields.size()));
        sql.delete(sql.length() - 2, sql.length());
        if (fields.stream().allMatch(DbFieldInfo::isPrimaryKey)) {
            return sql + ")\"";
        }

        sql.append(") on DUPLICATE KEY update ");

        for (DbFieldInfo field : fields) {
            if (! field.isPrimaryKey()) {
                sql.append("`").append(field.getColumnName()).append("`=?,");
            }
        }
        return sql.substring(0, sql.length() - 1) + "\"";
    }

    private static String createDeleteSql(String tableName, List<DbFieldInfo> fields) {
        StringBuilder sql = new StringBuilder();
        sql.append("\"delete from " + tableName);
        sql.append(" where ");
        for (int i = 0; i < fields.size(); i++) {
            if (! fields.get(i).isPrimaryKey()) {
                continue;
            }
            sql.append("`").append(fields.get(i).getColumnName()).append("`=?");
            sql.append(" and ");
        }
        if (sql.lastIndexOf(" and ") > 0) {
            sql.delete(sql.length() - 5, sql.length());
        }

        sql.append("\"");
        return sql.toString();
    }

    private static String createGetByIDSql(String tableName, List<DbFieldInfo> fields) {
        StringBuilder sql = new StringBuilder();
        sql.append("\"select * from " + tableName);
        sql.append(" where ");
        for (int i = 0; i < fields.size(); i++) {
            if (! fields.get(i).isPrimaryKey()) {
                continue;
            }
            sql.append("`").append(fields.get(i).getColumnName()).append("`=?");
            sql.append(" and ");
        }
        if (sql.lastIndexOf(" and ") > 0) {
            sql.delete(sql.length() - 5, sql.length());
        }

        sql.append(";\"");
        return sql.toString();
    }

    private static String fixSqlType(String originType) {
        String _type;
        switch (originType) {
            case "INT" -> _type = "INTEGER";
            case "DATETIME" -> _type = "TIMESTAMP";
            case "TEXT" -> _type = "LONGVARCHAR";
            default -> _type = originType;
        }
        return _type;
    }

    private static String createSetParams(String paramName, String var, String type, String entityName) {
        String _type = fixSqlType(type);
        StringBuilder result = new StringBuilder();
        result.append(paramName).append(".put(").append("Types.").append(_type)
                .append(", " + CommonUtil.CreateEntityParameterName(entityName) + ".");
        result.append("get" + CommonUtil.toUpperName(var) + "());");
        return result.toString();
    }

    private static String createSetParams(String paramName, String var, String type, int index) {
        String _type = fixSqlType(type);
        StringBuilder result = new StringBuilder();
        result.append(paramName).append(".put(").append("Types.").append(_type).append(",ids[" + index + "]);");
        return result.toString();
    }

    private static String createSetParams(String paramName, String var, String type) {
        String _type = fixSqlType(type);
        StringBuilder result = new StringBuilder();
        result.append("\t\t").append(paramName).append(".put(").append("Types.").append(_type).append(", "+ CamelCaseConverter.toCamelCase(var, true) + ");");
        return result.toString();
    }

    private static StringBuilder createSet(String objName, String var, String type) {
        if (type.equals("int"))
            type = "Int";
        if (type.equals("float"))
            type = "Float";
        if (type.equals("long"))
            type = "Long";
        if (type.equals("boolean"))
            type = "Boolean";
        if (type.equals("Timestamp"))
            type = "Date";
        if (type.equals("java.math.BigDecimal")) {
            type = "BigDecimal";
        }
        if (type.equals("java.sql.Date")) {
            type = "Date";
        }
        StringBuilder result = new StringBuilder();
        result.append(objName).append(".");
        result.append("set" + CommonUtil.toUpperName(var) + "(rs.get" + type + "(");
        result.append("\"").append(var).append("\"").append("));\n");
        return result;
    }
}
